<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body{
            padding-bottom: 800px;
            padding-left: 30px;
        }
        table{
            border-collapse: collapse;
            border-spacing: 0px;
        }
        td{
            border:  1px solid black;
            padding: 4px 10px;
        }
    </style>
</head>
<body>
    <div id="app">
        <h4>可控 watch 侦听器【监视器】</h4>
        <!-- 
            在vue的 mount 函数完成挂载后返回的vue实例对象中，存在一个 $watch 函数，该函数可以完成可控侦听器的定义
            $watch 使用语法
                unwatch = vm.$watch( expOrFn, callback, [options] )
                    参数
                        expOrFn: 描述被监视的数据变量名称(String)，对象属性取值路径名称
                                 通过接受方法参数，可以完成多变量的同时监控(方法内部通过变量调用规则完成监视器定义)
                                        => 方法内部荣国return定义关联变量 , 监视器回调函数的newValue和oldValue是关联方法的返回值
                        callback: 侦听器触发时的回调函数
                        options: { deep:Boolean(false),immediate:Boolean(false) }
                    返回值
                        unwatch:Function 该方法被调用时，会关闭对应的监视器
            
            面试题：vue如何同时监控多个变量的变化？
                        $watch
                        computed
         -->
        <p>msg:{{ msg }}</p>
        <input type="text" v-model="msg" >
        <h5>vue数据仓库中的 msg 变量被修改的时候记录 所有修改日志</h5>
        <input type="button" value="开启|关闭日志" @click="openOrCloseLogWatch()">
        <table>
            <thead>
                <tr>
                    <td>序号</td>
                    <td>时间</td>
                    <td>修改前数据</td>
                    <td>修改后数据</td>
                </tr>
            </thead>
            <tbody>
                <tr v-for=" (log,i) in logs ">
                    <td>{{ i+1 }}</td>
                    <td>{{ log.time }}</td>
                    <td>{{ log.oldValue }}</td>
                    <td>{{ log.value }}</td>
                </tr>
            </tbody>
        </table>
        <hr>
        <p>num1:{{ num1 }} <input type="number" v-model="num1"> </p>
        <p>num2:{{ num2 }} <input type="number" v-model="num2"> </p>
        <p>sum:{{ num1+num2 }}</p>
        <p>computed-sum:{{ sum }}</p>

        <input type="button" value="开启求和结果监控" @click="openSumWatch()">
    </div>
    <script type="module">
        // 加载 Vue3 的ESM 模块文件
        import { createApp } from "../assets/vue3/vue.esm-browser.js"
        window.vm = createApp({
            data(){
                return {
                    msg:"msg",
                    logs:[],
                    // unMsgwatch:null,
                    num1:10,
                    num2:20
                }
            },
            computed: {
                sum() {
                    return this.num1+this.num2 
                }
            },
            watch: {
                // msg:function(nv,ov){
                //     console.log("msg被修改时")
                //     this.logs.push({
                //         time:new Date().toLocaleString(),
                //         // value:this.msg,
                //         value:nv,
                //         oldValue:ov
                //     })
                // },
                sum(nv,ov){
                    console.log("computed-求和结果发生变化:",nv,ov)
                }
            },
            methods: {
                openOrCloseLogWatch() {
                    console.log(this)
                    // 如果需要在vue中完成一个非响应式变量的中转记录，可以直接为vue实例对象进行普通属性的定义和加载
                    // 但为了区分 vue实例对象中，那些变量或方法时vue的响应式变量或仓库方法，vue建议直接为vue实例绑定的属性或方法以 $ 开头
                    // if( this.unMsgwatch ){
                    //     // console.log(unMsgwatch)
                    //     this.unMsgwatch();
                    //     this.unMsgwatch = null;
                    // }else{
                    //     this.unMsgwatch = this.$watch("msg",(nv,ov)=>{
                    //         console.log("msg被修改")
                    //         this.logs.push({
                    //             time:new Date().toLocaleString(),
                    //             // value:this.msg,
                    //             value:nv,
                    //             oldValue:ov
                    //         })
                    //     })
                    // }
                    if( this.$unMsgwatch ){
                        this.$unMsgwatch();
                        this.$unMsgwatch = null;
                    }else{
                        this.$unMsgwatch = this.$watch("msg",(nv,ov)=>{
                            console.log("msg被修改")
                            this.logs.push({
                                time:new Date().toLocaleString(),
                                // value:this.msg,
                                value:nv,
                                oldValue:ov
                            })
                        })
                    }
                },
                openSumWatch(){
                    this.$watch(
                        ()=>{
                            // 定义监视器需要监视的相关变量
                            // return this.num1 + this.num2;
                            return [this.num1,this.num2]
                        },
                        (nv,ov)=>{
                            // 相关变量发生变化后的回调执行函数
                            console.log("求和结果发生变化:",nv,ov)
                        }
                    )
                }
            },
        }).mount("#app")
    </script>
</body>
</html>